package pikes.ecma;

import java.io.IOException;

import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

import pikes.ecma.Addition;
import pikes.ecma.Assignment;
import pikes.ecma.EcmaSyntaxVisitingException;
import pikes.ecma.FormattingScriptPrinter;
import pikes.ecma.FunctionDeclaration;
import pikes.ecma.Identifier;
import pikes.ecma.MemberPropertyAccess;
import pikes.ecma.SourceElement;
import pikes.ecma.StringLiteral;
import pikes.ecma.SyntaxTreeVisitor;
import pikes.ecma.VariableStatement;

public class ScriptPrinterTestCase {

	private StringBuilder appendable = null;

	@Before
	public void setup() {
		appendable = new StringBuilder();
	}

	@Test
	public void noPrinting() throws Exception {
		new FormattingScriptPrinter(appendable);

		Assert.assertEquals("", appendable.toString());
	}

	@Test
	public void oneSourceElement() throws Exception {
		FormattingScriptPrinter printer = new FormattingScriptPrinter(appendable);

		printer.visitSourceElement(new SourceElement() {

			public void print(Appendable appendable) throws IOException {
				appendable.append("test");

			}

			public void visit(SyntaxTreeVisitor syntaxTreeVisitor) throws EcmaSyntaxVisitingException {
				// TODO Auto-generated method stub

			}

		});

		Assert.assertEquals("test", appendable.toString());
	}

	@Test
	public void twoSourceElement() throws Exception {
		FormattingScriptPrinter printer = new FormattingScriptPrinter(appendable);

		printer.visitSourceElement(new SourceElement() {

			public void print(Appendable appendable) throws IOException {
				appendable.append("test");

			}

			public void visit(SyntaxTreeVisitor syntaxTreeVisitor) throws EcmaSyntaxVisitingException {
				// TODO Auto-generated method stub

			}

		});
		printer.visitSourceElement(new SourceElement() {

			public void print(Appendable appendable) throws IOException {
				appendable.append("test1");

			}

			public void visit(SyntaxTreeVisitor syntaxTreeVisitor) throws EcmaSyntaxVisitingException {
				// TODO Auto-generated method stub

			}

		});

		Assert.assertEquals("testtest1", appendable.toString());
	}

	@Test
	public void twoSourceElementInNewLines() throws Exception {
		FormattingScriptPrinter printer = new FormattingScriptPrinter(appendable, true);

		printer.visitSourceElement(new SourceElement() {

			public void print(Appendable appendable) throws IOException {
				appendable.append("test");

			}

			public void visit(SyntaxTreeVisitor syntaxTreeVisitor) throws EcmaSyntaxVisitingException {
				// TODO Auto-generated method stub

			}

		});
		printer.visitSourceElement(new SourceElement() {

			public void print(Appendable appendable) throws IOException {
				appendable.append("test1");

			}

			public void visit(SyntaxTreeVisitor syntaxTreeVisitor) throws EcmaSyntaxVisitingException {
				// TODO Auto-generated method stub

			}

		});

		Assert.assertEquals("test\ntest1\n", appendable.toString());
	}

	@Test
	public void beforeParameterList() throws Exception {
		FormattingScriptPrinter printer = new FormattingScriptPrinter(appendable);

		printer.beforeParameterList();

		Assert.assertEquals("(", appendable.toString());
	}

	@Test
	public void afterParameterList() throws Exception {
		FormattingScriptPrinter printer = new FormattingScriptPrinter(appendable);

		printer.afterParameterList();

		Assert.assertEquals(")", appendable.toString());
	}

	@Test
	public void comma() throws Exception {
		FormattingScriptPrinter printer = new FormattingScriptPrinter(appendable);

		printer.comma();

		Assert.assertEquals(",", appendable.toString());
	}

	@Test
	public void beforeFunctionBlock() throws Exception {
		FormattingScriptPrinter printer = new FormattingScriptPrinter(appendable);

		printer.openCurlyBrace();

		Assert.assertEquals("{", appendable.toString());
	}

	@Test
	public void beforeFunctionBlock1() throws Exception {
		FormattingScriptPrinter printer = new FormattingScriptPrinter(appendable);
		printer.setSpaceBeforeOpeningBrace(true);

		printer.openCurlyBrace();

		Assert.assertEquals(" {", appendable.toString());
	}

	@Test
	public void beforeFunctionBlock2() throws Exception {
		FormattingScriptPrinter printer = new FormattingScriptPrinter(appendable);
		printer.setStartBlockInNewLine(true);

		printer.openCurlyBrace();

		Assert.assertEquals("{\n", appendable.toString());
	}

	@Test
	public void afterFunctionBlock() throws Exception {
		FormattingScriptPrinter printer = new FormattingScriptPrinter(appendable);

		printer.closeCurlyBrace();

		Assert.assertEquals("}", appendable.toString());
	}

	@Test
	public void beforeVariableDeclaration() throws Exception {
		FormattingScriptPrinter printer = new FormattingScriptPrinter(appendable);

		printer.beforeVariableDeclarations();

		Assert.assertEquals("var ", appendable.toString());
	}

	@Test
	public void identifier() throws Exception {
		FormattingScriptPrinter printer = new FormattingScriptPrinter(appendable);

		printer.identifier("id");

		Assert.assertEquals("id", appendable.toString());
	}

	@Test
	public void endOfStatement() throws Exception {
		FormattingScriptPrinter printer = new FormattingScriptPrinter(appendable);

		printer.endOfStatement();

		Assert.assertEquals(";", appendable.toString());
	}

	@Test
	public void binaryOperation() throws Exception {
		FormattingScriptPrinter printer = new FormattingScriptPrinter(appendable);

		printer.binaryOperator("op");

		Assert.assertEquals("op", appendable.toString());
	}

	@Test
	public void dotOperation() throws Exception {
		FormattingScriptPrinter printer = new FormattingScriptPrinter(appendable);

		printer.dotOperator();

		Assert.assertEquals(".", appendable.toString());
	}

	@Test
	public void indent() throws Exception {
		FormattingScriptPrinter printer = new FormattingScriptPrinter(appendable);

		printer.setNewLineAfterEndOfStatement(true);
		printer.setStartBlockInNewLine(true);
		printer.setIndent(true);

		FunctionDeclaration funcDec = new FunctionDeclaration("go");
		funcDec.add("country");

		String url = "url";
		VariableStatement varDec = new VariableStatement(url, new Addition(new StringLiteral(
				"/countries/main/detail.htm?code="), new Identifier("country")));
		funcDec.add(varDec);
		funcDec.add(new Assignment(new MemberPropertyAccess("window", "location"), url));

		funcDec.visit(printer);

		Assert
				.assertEquals(
						"function go(country){\n        var url=\'/countries/main/detail.htm?code=\'+country;\n        window.location=url;\n}",
						appendable.toString());
	}
}
